package xin.marcher.module.replenished.repository;

import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;
import xin.marcher.module.inventory.domain.response.WarningInventoryDTO;
import xin.marcher.module.replenished.domain.bo.ProductSellerRelationBO;
import xin.marcher.module.replenished.domain.entity.ProductDetailDO;
import xin.marcher.module.replenished.generator.SegmentIDGen;
import xin.marcher.module.replenished.redis.RedisSortedSetCache;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * redis 和数据库交互相关的 资源类
 *
 *
 */
@Repository
public class RedisManagerRepository {

    @Autowired
    private SegmentIDGen segmentIDGen;

    /**
     * 获取每个缓存key存储的权重值
     *
     * @param cacheKey
     * @return
     */
    public Double getSortedSetScore(String cacheKey) {
        Long autoNo = segmentIDGen.genNewNo(cacheKey);

        return Double.valueOf(autoNo);
    }

    /**
     * 将缓存的数据转换为 实体对象
     *
     * @param redisSetMap
     * @return
     */
    public Map<Long, Map<String, ProductDetailDO>> converterProductSellerCache(Map<Long, List<String>> redisSetMap) {
        Map<Long, Map<String, ProductDetailDO>> productSellerRelationBOMap = new HashMap<>(redisSetMap.size());
        if (!CollectionUtils.isEmpty(redisSetMap)) {
            for (Map.Entry<Long, List<String>> entry : redisSetMap.entrySet()) {
                List<String> productSellerList = entry.getValue();
                Map<String, ProductDetailDO> productDetailMap = new HashMap<>(productSellerList.size());
                for (String content : productSellerList) {
                    ProductDetailDO productDetailDO = JSONObject.parseObject(content, ProductDetailDO.class);
                    productDetailMap.put(productDetailDO.getSkuId(), productDetailDO);
                }
                productSellerRelationBOMap.put(entry.getKey(), productDetailMap);
            }
        }
        return productSellerRelationBOMap;
    }

    /**
     * 对缓存差集的数据进行处理
     *
     * @param productSellerRelationBOList 待缓存的数据
     * @param productSellerCacheMap       缓存中已存在的数据
     * @param getRedisKeyFunction         缓存key
     * @return
     */
    public Map<String, RedisSortedSetCache> diffProduct(List<ProductSellerRelationBO> productSellerRelationBOList,
                                                        Map<Long, Map<String, ProductDetailDO>> productSellerCacheMap,
                                                        Function<Long, String> getRedisKeyFunction) {
        Map<String, RedisSortedSetCache> redisSortedSetCacheMap = new HashMap<>();
        //1. 处理缓存中需要新增的数据，删除数据
        Map<Long, ProductSellerRelationBO> productSellerRelationResidueMap = diffCacheAddOrDelete(productSellerRelationBOList, productSellerCacheMap, redisSortedSetCacheMap, getRedisKeyFunction);
        //2. 处理缓存中不存在的卖家数据，新增处理
        diffAddSellerCache(productSellerRelationResidueMap, redisSortedSetCacheMap, getRedisKeyFunction);
        //3.处理缓存中存在的卖家数据，结果不存在，删除处理
        diffDeleteSellerCache(productSellerCacheMap, redisSortedSetCacheMap, getRedisKeyFunction);
        return redisSortedSetCacheMap;
    }

    /**
     * 对预警的信息转换为对应缓存模型
     *
     * @param skuList             已缓存的预警sku对象
     * @param warningInventoryDTO 预警对象
     * @param getRedisKeyFunction 缓存key
     * @return
     */
    public Map<String, RedisSortedSetCache> diffWarningInventory(List<String> skuList, WarningInventoryDTO warningInventoryDTO, Function<String, String> getRedisKeyFunction) {
        Map<String, RedisSortedSetCache> redisSortedSetCacheMap = new HashMap<>();


        RedisSortedSetCache redisSortedSetCache = new RedisSortedSetCache();
        String key = warningInventoryDTO.getSellerId() + warningInventoryDTO.getSkuId();

        String redisKey = getRedisKeyFunction.apply(key);
        if (CollectionUtils.isEmpty(skuList)) {
            return redisSortedSetCacheMap;
        }
        for (String skuId : skuList) {
            if (skuId.equals(warningInventoryDTO.getSkuId())) {
                return redisSortedSetCacheMap;
            }
        }
        redisSortedSetCache.getAddMap().put(JSONObject.toJSON(warningInventoryDTO).toString(), getSortedSetScore(redisKey));
        redisSortedSetCacheMap.put(redisKey, redisSortedSetCache);
        return redisSortedSetCacheMap;
    }

    /**
     * 处理缓存中存在的卖家数据，结果不存在，删除处理
     *
     * @param productSellerCacheMap 缓存中已存在的数据
     * @param getRedisKeyFunction   缓存key
     * @return
     */
    private void diffDeleteSellerCache(Map<Long, Map<String, ProductDetailDO>> productSellerCacheMap,
                                       Map<String, RedisSortedSetCache> redisSortedSetCacheMap,
                                       Function<Long, String> getRedisKeyFunction) {
        // 当可售的列表中，不存在缓存已经存在的数据列表，说明缓存已经无效，需要删除该对应的key下的缓存信息
        if (!CollectionUtils.isEmpty(productSellerCacheMap)) {
            for (Map.Entry<Long, Map<String, ProductDetailDO>> entry : productSellerCacheMap.entrySet()) {
                Long key = entry.getKey();
                Map<String, ProductDetailDO> value = entry.getValue();
                if (CollectionUtils.isEmpty(value)) {
                    continue;
                }
                String redisKey = getRedisKeyFunction.apply(key);

                RedisSortedSetCache redisSortedSetCache = new RedisSortedSetCache();
                redisSortedSetCache.setDeleteKey(Boolean.TRUE);
                //设置到需要处理得缓存对象中
                redisSortedSetCacheMap.put(redisKey, redisSortedSetCache);
            }
        }
    }

    /**
     * 处理缓存中不存在的卖家数据，新增处理
     *
     * @param productSellerRelationMap 待缓存的数据
     * @param getRedisKeyFunction      缓存key
     * @return
     */
    private void diffAddSellerCache(Map<Long, ProductSellerRelationBO> productSellerRelationMap,
                                    Map<String, RedisSortedSetCache> redisSortedSetCacheMap,
                                    Function<Long, String> getRedisKeyFunction) {
        Iterator<Map.Entry<Long, ProductSellerRelationBO>> iterator = productSellerRelationMap.entrySet().iterator();
        // 对处理缓存差集后，还剩余的未处理数据做新增处理
        while (iterator.hasNext()) {
            Map.Entry<Long, ProductSellerRelationBO> entry = iterator.next();
            ProductSellerRelationBO productSellerRelation = entry.getValue();

            RedisSortedSetCache redisSortedSetCache = new RedisSortedSetCache();

            Long key = entry.getKey();

            String redisKey = getRedisKeyFunction.apply(key);

            // 卖家的处理后的可售商品列表
            List<ProductDetailDO> productDetailList = productSellerRelation.getProductDetailList();
            for (ProductDetailDO productDetailDO : productDetailList) {
                redisSortedSetCache.getAddMap().put(JSONObject.toJSON(productDetailDO).toString(), getSortedSetScore(redisKey));
            }
            //设置到需要处理得缓存对象中
            redisSortedSetCacheMap.put(redisKey, redisSortedSetCache);
        }

    }


    /**
     * 处理缓存中需要新增的数据，删除数据
     *
     * @param productSellerRelationBOList 待缓存的数据
     * @param productSellerCacheMap       缓存中已存在的数据
     * @param getRedisKeyFunction         缓存key
     * @return
     */
    private <T> Map<Long, ProductSellerRelationBO> diffCacheAddOrDelete(List<ProductSellerRelationBO> productSellerRelationBOList,
                                                                        Map<Long, Map<String, ProductDetailDO>> productSellerCacheMap,
                                                                        Map<String, RedisSortedSetCache> redisSortedSetCacheMap,
                                                                        Function<Long, String> getRedisKeyFunction) {
        Map<Long, ProductSellerRelationBO> productSellerRelationResidueMap = new HashMap<>(productSellerRelationBOList.size());
        for (ProductSellerRelationBO productSellerRelation : productSellerRelationBOList) {

            RedisSortedSetCache redisSortedSetCache = new RedisSortedSetCache();
            Long sellerId = productSellerRelation.getSellerId();

            String redisKey = getRedisKeyFunction.apply(sellerId);
            // 命中了缓存的数据，开始进行差集处理
            if (productSellerCacheMap.containsKey(sellerId)) {
                // 获取当前这个卖家下的缓存商品信息，key为商品sku
                Map<String, ProductDetailDO> productDetailDOMap = productSellerCacheMap.get(sellerId);
                // 卖家的处理后的可售商品列表
                List<ProductDetailDO> productDetailList = productSellerRelation.getProductDetailList();

                // 处理返回差异的数据结果，需新增或者删除的数据集合
                for (ProductDetailDO productDetailDO : productDetailList) {
                    //命中了则说明无差异，不处理，从集合中移除
                    if (!CollectionUtils.isEmpty(productDetailDOMap) && productDetailDOMap.containsKey(productDetailDO.getSkuId())) {
                        productDetailDOMap.remove(productDetailDO.getSkuId());
                        continue;
                    }
                    // 未命中，说明这个数据缓存中不存在，做新增处理
                    redisSortedSetCache.getAddMap().put(JSONObject.toJSONString(productDetailDO), getSortedSetScore(redisKey));
                }
                // 遍历处理完成之后，缓存中还有多余的对象都属于无效数据，需要删除
                if (!CollectionUtils.isEmpty(productDetailDOMap)) {
                    for (Map.Entry<String, ProductDetailDO> entry : productDetailDOMap.entrySet()) {
                        redisSortedSetCache.getDeleteMemberSet().add(JSONObject.toJSONString(entry.getValue()));
                    }
                }
                //设置到需要处理得缓存对象中
                redisSortedSetCacheMap.put(redisKey, redisSortedSetCache);

                // 删除处理掉的缓存对象
                productSellerCacheMap.remove(sellerId);
            } else {
                // 未命中缓存的 都是新增数据
                productSellerRelationResidueMap.put(sellerId, productSellerRelation);
            }
        }
        return productSellerRelationResidueMap;
    }

    /**
     * 对没有可售商品的缓存卖家 构建成对应的删除对象
     *
     * @param redisSortedSetCacheMap
     * @param productSellerRelationBOMap
     * @param cacheKey
     */
    private void buildDeleteSortedSetCache(Map<String, RedisSortedSetCache> redisSortedSetCacheMap, Map<String, Map<String, ProductDetailDO>> productSellerRelationBOMap, String cacheKey) {
        for (String key : productSellerRelationBOMap.keySet()) {
            RedisSortedSetCache redisSortedSetCache = new RedisSortedSetCache();
            redisSortedSetCache.setDeleteKey(Boolean.TRUE);
            //设置到需要处理得缓存对象中
            redisSortedSetCacheMap.put(cacheKey, redisSortedSetCache);
        }
    }


    /**
     * 对缓存差集的数据进行处理
     *
     * @param sellerSaleProductMap 待缓存的数据
     * @param redisSetMap          缓存中存在的数据
     * @param getRedisKeyFunction  获取缓存key的方法
     * @return
     */
    public <T> Map<String, RedisSortedSetCache> diffAvailableCache(Map<T, List<String>> sellerSaleProductMap,
                                                                   Map<T, List<String>> redisSetMap,
                                                                   Function<T, String> getRedisKeyFunction) {

        Map<String, RedisSortedSetCache> redisSortedSetCacheMap = new HashMap<>(sellerSaleProductMap.size());

        if (!CollectionUtils.isEmpty(sellerSaleProductMap)) {
            // 遍历待缓存的数据

            Iterator<Map.Entry<T, List<String>>> iterator = sellerSaleProductMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<T, List<String>> entry = iterator.next();

                RedisSortedSetCache redisSortedSetCache = new RedisSortedSetCache();
                T key = entry.getKey();

                // 命中了缓存的数据，开始进行差集处理
                if (redisSetMap.containsKey(key)) {
                    List<String> oldCacheValue = redisSetMap.get(key);
                    List<String> newCacheValue = sellerSaleProductMap.get(key);

                    // 取两个数据的差集，旧数据中有，新数据中没有的，表示这个数据是需要被删除的
                    List<String> delList = oldCacheValue.stream()
                            .filter(str -> !newCacheValue.contains(str))
                            .collect(Collectors.toList());

                    // 取两个数据的差集，新数据中有，旧数据中没有的，表示这个数据是新增的
                    List<String> addList = newCacheValue.stream()
                            .filter(str -> !oldCacheValue.contains(str))
                            .collect(Collectors.toList());

                    String redisKey = getRedisKeyFunction.apply(key);
                    for (String str : addList) {
                        redisSortedSetCache.getAddMap().put(str, getSortedSetScore(redisKey));
                    }
                    redisSortedSetCache.getDeleteMemberSet().addAll(delList);

                    // 处理过的数据需要移除，没处理的表示之前缓存中不存在的数据
                    iterator.remove();
                    // 处理过的数据需要移除，没处理的表示之前缓存中存在但是新的数据中不存在的数据，即需要删除的数据
                    redisSetMap.remove(key);

                    //设置到需要处理得缓存对象中
                    redisSortedSetCacheMap.put(redisKey, redisSortedSetCache);
                }
            }

            // 对处理缓存差集后，还剩余的未处理的待缓存数据做新增处理
            for (Map.Entry<T, List<String>> entry : sellerSaleProductMap.entrySet()) {
                RedisSortedSetCache redisSortedSetCache = new RedisSortedSetCache();
                T key = entry.getKey();
                String redisKey = getRedisKeyFunction.apply(key);
                for (String str : entry.getValue()) {
                    redisSortedSetCache.getAddMap().put(str, getSortedSetScore(redisKey));
                }

                //设置到需要处理得缓存对象中
                redisSortedSetCacheMap.put(redisKey, redisSortedSetCache);
            }
        }

        // 对处理缓存差集后，还剩余的缓存中的数据做删除处理
        for (T key : redisSetMap.keySet()) {
            RedisSortedSetCache redisSortedSetCache = new RedisSortedSetCache();
            String redisKey = getRedisKeyFunction.apply(key);
            redisSortedSetCache.setDeleteKey(Boolean.TRUE);
            //设置到需要处理得缓存对象中
            redisSortedSetCacheMap.put(redisKey, redisSortedSetCache);
        }

        return redisSortedSetCacheMap;
    }
}
